/**
 *
 * Copyright  2011 Nokia Corporation.
 * tuomo.hirvonen@digia.com
 *
 * FONT SAVE FOR GIMP
 !"#$% �()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
 */


#include <QDebug>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "thegame.h"
#include "storelauncher.h"


const char *difficultyStrings[] = {
        "BEGINNER",
        "EASY",
        "AVERAGE",
        "DIFFICULT",
        "MASTER",
        0
};


/*
        "FLAGMINES V1.2 LITE",
        "(C) DIGIA 2012",

        "OPEN TILES BY CLICKING",
        "MARK/UNMARK MINES BY LONG",
        "TAPPING. SCROLL SCREEN BY",
        "SWEEPING. PINCH TO ZOOM",


         // get full version





*/

#ifdef LITE_VERSION
#define CROSS_FADER_STRING_COUNT 11
const char *crossFaderStrings[] = {
        "FLAGMINES V1.2 LITE",
        "(C) DIGIA LTD. 2012",
        "GET THE FULL VERSION FROM",
        "THE OVISTORE:",
        "3 MORE DIFFICULTY LEVELS",
        "FOR A SERIOUS CHALLENGE",
        "...",
        "OPEN TILES BY CLICKING",
        "MARK/UNMARK MINES BY LONG",
        "TAPPING. SCROLL SCREEN BY",
        "SWEEPING. PINCH TO ZOOM",
        0
};

const bool activeDifficulties[] = {         // only 2 easiest difficulties enabled.
    true,
    true,
    false,
    false,
    false
};
#else
#define CROSS_FADER_STRING_COUNT 7
const char *crossFaderStrings[] = {
        "FLAGMINES V1.2",
        "(C) DIGIA LTD. 2012",
        "OPEN TILES BY CLICKING",
        "MARK/UNMARK MINES BY",
        "LONG TAPPING",
        "SCROLL SCREEN BY SWEEPING",
        "PINCH TO ZOOM",
        0
};
const bool activeDifficulties = 0;          // no difficulties disabled.
#endif

const char *inGameMenu[] = {
        "CONTINUE",
        "RESTART",
        "MENU",
        "QUIT",
        0
};


const char *gameoverMenu[] = {
        "RESTART",
        "MENU",
        "QUIT",
        0
};


const int difficultyMines[] = { 10,13,18,20,23 };         // percentage of mines
const int difficultyLevelSize[] = {10,14,17,23,30 };      // The size (width and height) of the level


TheGame::TheGame( SpriteBatch *sbatch ) {

    waitBeforeCreatingMenu = 0.0f;
    resetCrossFader();
    launchOviClient = false;
    menu = 0;
    tempAngle = 0.0f;
    scrollBarVisibility = 0.0f;
    spriteBatch = sbatch;
    closeButtonActivated = false;
    level = 0;
    difficulty = 0;
    pressing = false;
    exitFlag = false;
    cameraPos[0] = 0.0f;
    cameraPos[1] = 0.0f;
    potentialMove[0] = 0.0f;
    potentialMove[1] = 0.0f;
    particles = new ParticleSystem( this );

    // Create particle sprays
    ParticleSystem::initSprayType( &explosionSpray, 6,0,0,0,0.4f,0.1f, BLOCK_SIZE, 0.0f, 1300.0f,0.0f,0,10.0f, -10.0f, 10.0f );
    ParticleSystem::initSprayType( &starSpray, 7,0,0,1.0f,0.5f,1.0f, 20, 20.0f, -100.0f,200.0f,0,10.0f, -10.0f, 10.0f );
#ifdef Q_OS_SYMBIAN
    ParticleSystem::initSprayType( &sparkleSpray, 6,0,900.0f,3.0f,0.5f,1.0f, 5.0f, 5.0f, -15.0f,0.0f,0,10.0f, -10.0f, 10.0f );
#else
    ParticleSystem::initSprayType( &sparkleSpray, 6,0,900.0f,3.0f,0.5f,1.0f, 7.0f, 7.0f, -15.0f,0.0f,0,10.0f, -10.0f, 10.0f );
#endif

    sparkleSpray.col[0] = 1.0f;
    sparkleSpray.col[1] = 0.8f;
    sparkleSpray.col[2] = 0.2f;
    sparkleSpray.col[3] = 1.0f;
}


TheGame::~TheGame() {
    delete particles;
    if (level) delete level;
    if (menu) delete menu;

}

void TheGame::newGame() {
        // difficulty
    if (level) delete level;
    level = new TheLevel(this, difficultyLevelSize[difficulty],difficultyLevelSize[difficulty], difficultyMines[difficulty]);
    gameTime = 0.0f;
    finishedCounter = 1.0f;
}

void TheGame::cancelPress() {
    longClickPossible = false;
    clickPossible = false;
    pressing = false;
}

void TheGame::press( float x, float y) {

    longClickPossible = true;
    clickPossible = true;

        // check if the stopping kinetic-movement disables the possibility for a clicks
    if ( sqrtf( potentialMove[0] * potentialMove[0] + potentialMove[1]*potentialMove[1])>100.0f) {
        potentialMove[0] = 0.0f;
        potentialMove[1] = 0.0f;
        clickPossible = false;
        longClickPossible = false;
    }


    pressDownPos[0] = x;
    pressDownPos[1] = y;
    exPressPos[0] = x;
    exPressPos[1] = y;

    pressTime = 0.0f;
    pressing = true;

    if (menu) {
            // See if the press hits a menu item.
        if (menu->mousedown(x,y)) {
            // It did, it cannot cause any other events.
            longClickPossible = false;
            clickPossible  = false;
        } else {
            if (level && level->isGameOver()==false && level->isLevelCompleted() == false) {
                delete menu;
                menu = 0;
                clickPossible = false;
                longClickPossible = false;
            }
        }
    }
}


void TheGame::move( float x, float y ) {
    if (!pressing) return;
    if (level && level->isShowingMap()) return;


        // Delta from previous pressposition and current.
    float dx = -(exPressPos[0] - x);
    float dy = -(exPressPos[1] - y);

        // Check if we've moved too far from the original pressDown - position.
        // Disable click if so
    if (clickPossible) {
        if (sqrtf( dx*dx + dy*dy) > CLICK_RADIUS ) clickPossible = false;
        return;
    }

        // Move camera
    scrollBarVisibility = 2.0f;
    cameraPos[0] += dx;
    cameraPos[1] += dy;
    exPressPos[0] = x;
    exPressPos[1] = y;
}



void TheGame::release( float x, float y) {
    if (pressing == false) return;          // long click has been already done.
    //if (level && level->isShowingMap()) return;

    if (menu) {
        int menuCommand = menu->mouseup(x,y);

            // Menu sent a command.
        if (menuCommand!=-1) {
            if (!level) {               // Difficulty selection
#ifdef LITE_VERSION
                if (menuCommand>1) {
                    waitBeforeCreatingMenu = 3.5f;
                    launchOviClient = true;

                } else {
                    difficulty = menuCommand;
                    newGame();
                }
#else
                difficulty = menuCommand;
                newGame();
#endif

            } else {                    // IngameMenu
                if (level->isGameOver() == false && level->isLevelCompleted()==false) {
                    qDebug() << "ingamemenu!!: " << menuCommand;
                    switch (menuCommand) {
                    case 0: /* continue. Do nothing */ break;
                    case 1: newGame(); break;                   // restart
                    case 2: delete level; level = 0; break;     // main menu
                    case 3: exitFlag = true; break;             // quit
                    }
                } else {                // gameover menu
                    qDebug() << "Processgameovermenu: " << menuCommand;
                    switch (menuCommand) {
                    case 0: newGame(); break;                   // restart
                    case 1: delete level; level = 0; break;     // main menu
                    case 2: exitFlag = true; break;             // quit
                    }
                }
            }

            delete menu;
            menu = 0;
        }
    };



    pressing = false;
    float ftemp;
    float dx = -(pressDownPos[0]-x);
    float dy = -(pressDownPos[1]-y);
    ftemp = sqrtf( dx*dx+dy*dy );

        // Was a click
    if (ftemp<CLICK_RADIUS) {

        if (clickPossible) {

                // Handle the close button
            if (x>spriteBatch->getTargetWidth()-90 && y>spriteBatch->getTargetHeight() - 90) {
                if (!level) exitFlag = true;
                if (closeButtonActivated || level) {
                    if (level) {            // Back to the main menu
                        if (menu) {
                            delete level;
                            level = 0;
                            delete menu;
                            menu = 0;
                        } else {
                            if (level->isGameOver() == false)
                                menu = new TheMenu( this, inGameMenu );
                            else
                                menu = new TheMenu( this, gameoverMenu );
                        }
                        closeButtonActivated = false;
                        return;
                    } else exitFlag = true;
                } else closeButtonActivated = true;
                return;
            } else closeButtonActivated = false;


            // Send to the level if it's active
            if (!menu && level && level->isGameOver()==false && level->isLevelCompleted()==false) {
                if (level->isShowingMap()==true) {
                    cameraPos[0] = -x / (float)spriteBatch->getTargetWidth();
                    float yp = y-(spriteBatch->getTargetHeight() - spriteBatch->getTargetWidth())/2;
                    cameraPos[1] = -yp / (float)spriteBatch->getTargetWidth();
                    cameraPos[0] = cameraPos[0] * level->getWidth()*BLOCK_SIZE  + spriteBatch->getTargetWidth() - BLOCK_SIZE;
                    cameraPos[1] = cameraPos[1] * level->getHeight()*BLOCK_SIZE + spriteBatch->getTargetHeight() - BLOCK_SIZE;

                }
                level->click( x-cameraPos[0], y-cameraPos[1] );
            }
        }
    }
    else
    {
        if (pressTime<KINETIC_SWEEP_TIME) {
                // Add sweep to potential movement
            ftemp=1.5f / (pressTime);
            potentialMove[0] = (dx) * ftemp * KINETIC_MOVEMENT_POWER;
            potentialMove[1] = (dy) * ftemp * KINETIC_MOVEMENT_POWER;
                // Stop if too slow
            ftemp = sqrtf( potentialMove[0] * potentialMove[0] + potentialMove[1]*potentialMove[1]);
            if (ftemp<KINETIC_STOP_SPEED) {
                potentialMove[0] = 0.0f;
                potentialMove[1] = 0.0f;
            }
        }

    }

}



/**
 *
 * Run the game logic's platform independent parts.
 * Returns true while the game is running, false if it should be exitesd.
 *
 */
bool TheGame::update( const float frameTime ) {
    tempAngle += frameTime;
        // Either increase the gametime or finishedCounter
        // (which will animate the completion texts (over/done).
    if (level && level->isGameOver()==false && level->isLevelCompleted()==false) {
        if (menu==0) gameTime+=frameTime;
    } else {
        finishedCounter -= finishedCounter * frameTime * 4.0f;
    }


    crossFaderCounter+=frameTime;
    if (crossFaderCounter>=1.0f) {
        crossFaderCounter-=1.0f;
        if (crossFaderCounter>=1.0f) crossFaderCounter = 0.0f;          // Force to zero, just in case
        crossFaderState++;
        if (crossFaderState>2) {
            crossFaderState = 0;
            crossFaderString++;
            if (crossFaderString>=CROSS_FADER_STRING_COUNT) crossFaderString = 0;
        }
    }




    if (!level) {
        cameraPos[0] = 0.0f;
        cameraPos[1] = 0.0f;
    }


        // If there is no level nor menu, create the mainmenu
    if (menu==0 && level==0) {
        if (waitBeforeCreatingMenu>0.0f)
            waitBeforeCreatingMenu-=frameTime;
        else {
            menu = new TheMenu( this, difficultyStrings, activeDifficulties );
            resetCrossFader();
            closeButtonActivated = false;
        }
    }

        // If there is level but no menu and the level is ended.
        // Create the ingame menu
    if (level && menu==0 && (level->isGameOver() || level->isLevelCompleted())) {
        menu = new TheMenu( this, gameoverMenu );
    }


    if (menu) menu->update( frameTime );


        // Camera movement
    if (pressing) {
        pressTime+=frameTime;

        if (longClickPossible) {
            float dx = (exPressPos[0]-pressDownPos[0]);
            float dy = (exPressPos[1]-pressDownPos[1]);
            float ftemp = sqrtf( dx*dx+dy*dy );
                // Was a long click
            if (ftemp<CLICK_RADIUS) {
                if (pressTime>LONG_CLICK_TIME) {
                    if (!menu && level) level->longClick( exPressPos[0]-cameraPos[0], exPressPos[1]-cameraPos[1] );
                    pressing = false;
                }
            } else longClickPossible = false;
        }
    }


    if (level && level->isShowingMap() == false) {
            // Kinetic movevement
        float m = sqrtf( potentialMove[0] * potentialMove[0] + potentialMove[1]*potentialMove[1]);
        if (m<KINETIC_STOP_SPEED/4.0f) {
            potentialMove[0] = 0.0f;
            potentialMove[1] = 0.0f;
        } else scrollBarVisibility = 2.0f;      // scrollbars are visible

        cameraPos[0] += potentialMove[0] * frameTime;
        cameraPos[1] += potentialMove[1] * frameTime;
        potentialMove[0] -= potentialMove[0] * frameTime * 2.0f;
        potentialMove[1] -= potentialMove[1] * frameTime * 2.0f;
    }

    if (scrollBarVisibility>0.0f)
        scrollBarVisibility -= frameTime*2.0f;


        // Level update
    if (level && pressing == false) {
            // Limit the camera position
        float xmin = -level->getWidth()*BLOCK_SIZE + spriteBatch->getTargetWidth() - spriteBatch->getTargetWidth()/4 + BLOCK_SIZE/2;
        float ymin = -level->getHeight()*BLOCK_SIZE + spriteBatch->getTargetHeight() - spriteBatch->getTargetHeight()/4 + BLOCK_SIZE/2;
        float xmax = spriteBatch->getTargetWidth()/4;
        float ymax = spriteBatch->getTargetHeight()/4;

        if (cameraPos[0]<xmin) cameraPos[0] += (xmin-cameraPos[0]) * frameTime * CAMERA_LIMIT_STRENGTH;
        if (cameraPos[1]<ymin) cameraPos[1] += (ymin-cameraPos[1]) * frameTime * CAMERA_LIMIT_STRENGTH;
        if (cameraPos[0]>xmax) cameraPos[0] += (xmax-cameraPos[0]) * frameTime * CAMERA_LIMIT_STRENGTH;
        if (cameraPos[1]>ymax) cameraPos[1] += (ymax-cameraPos[1]) * frameTime * CAMERA_LIMIT_STRENGTH;

            // Run the level
        level->update( frameTime );
    }

    if (particles) particles->run( frameTime );

    if (level) {
        if (menu) closeButtonActivated = true; else closeButtonActivated = false;
    }


        // Should we keep running
    if (exitFlag) return false; else return true;
}


void TheGame::resetCrossFader() {
    crossFaderCounter = 0.0f;
    crossFaderString = 0;
    crossFaderState = 0;    // fade in
}





void TheGame::renderMainScreen() {
        // Render the logo
#ifdef Q_OS_SYMBIAN
    const float logoscale = 420 * (1.0f + cosf( tempAngle * 0.1f) * 0.1f);
    const float burnPosX = spriteBatch->getTargetWidth()/2 + 58;
    const float burnPosY = spriteBatch->getTargetHeight()/5-73;
#else
    const float logoscale = 540 * (1.0f + cosf( tempAngle * 0.1f) * 0.1f);
    const float burnPosX = spriteBatch->getTargetWidth()/2 + 70;
    const float burnPosY = spriteBatch->getTargetHeight()/5-96;

#endif

    SpriteDrawInfo sdi;
    sdi.textureHandle = gameTextures.logoTexture;
    sdi.setTargetPos(spriteBatch->getTargetWidth()/2, spriteBatch->getTargetHeight()/5);
    sdi.setScale(logoscale);
    spriteBatch->draw( &sdi );



        // spray some sparke particles from the bomb
#ifdef Q_OS_SYMBIAN
    particles->spray( 1, burnPosX,burnPosY, 4.0f, 0,0, 200.0f, &sparkleSpray );
    if (((rand() & 255) < 32)) {
        particles->spray( 4+(rand() & 7), burnPosX,burnPosY, 8.0f,
                          (-1.0f + (rand()&1)*2.0f) * 300.0f,((rand()&255)-128)*6.0f, 40.0f + (rand()&3)*100.0f, &sparkleSpray );
    }
#else
    particles->spray( 1, burnPosX,burnPosY, 8.0f, 0,0, 280.0f, &sparkleSpray );
    if (((rand() & 255) < 32)) {
        particles->spray( 4+(rand() & 7), burnPosX,burnPosY, 8.0f,
                          (-1.0f + (rand()&1)*2.0f) * 400.0f,((rand()&255)-128)*8.0f, 60.0f + (rand()&3)*140.0f, &sparkleSpray );
    }
#endif


        // render a flare ontop of the burning string.
    sdi.textureHandle = gameTextures.iconTexture;
    sdi.setSourceRect(0.5, 0.5, 0.25f, 0.5f );
    sdi.setTargetPos(burnPosX, burnPosY );

    sdi.r = 1.0f;
    sdi.g = 0.9f;
    sdi.b = 0.7f;
    //sdi.a = 0.5f;
    int t = (rand() & 15);
#ifdef Q_OS_SYMBIAN
    sdi.setScale( 80 +  (t*t)/10.0f);
#else
    sdi.setScale( 120 +  (t*t)/10.0f);
#endif
    sdi.angle = (rand() & 255) / 16.0f;
    spriteBatch->draw( &sdi );


    // Render the crossFader
    float col[4];
    col[0] = 1.0f;
    col[1] = 1.0f;
    col[2] = 1.0f;
    col[3]=1.0f;
    if (crossFaderState==0) col[3] = crossFaderCounter;
    if (crossFaderState==2) col[3] = 1.0f - crossFaderCounter;



    writeText( spriteBatch, crossFaderStrings[crossFaderString],
               (spriteBatch->getTargetWidth() - strlen(crossFaderStrings[crossFaderString])*FONT_X_INC_MUL*16.0f)/2.0f,
               spriteBatch->getTargetHeight()/5 + 106.0f, 16.0f,col );


}

void TheGame::renderHud() {
    // Draw the hud
    char testr[256];
    writeText(spriteBatch, "TIME", 14,14,22.0f);
    int secs = (int)gameTime;
    int mins = secs / 60;
    secs -= mins*60;
    sprintf( testr, "%.2d:%.2d", mins, secs );
    writeText( spriteBatch, testr,  22,40,50 );

    writeText(spriteBatch, "MINES", 14, spriteBatch->getTargetHeight()-56,22 );
    sprintf(testr, "%d/%d", level->getTotalMinerMarks(), level->getTotalMines() );
    writeText( spriteBatch, testr, 22,spriteBatch->getTargetHeight()-25,50 );

    // difficulty text
    writeText(spriteBatch, difficultyStrings[ difficulty ],
              spriteBatch->getTargetWidth()-22*FONT_X_INC_MUL * strlen( difficultyStrings[difficulty]),
              14, 22 );


    // scrollbars
    if (scrollBarVisibility>0.0f) {
        SpriteDrawInfo sdi;
        sdi.textureHandle = gameTextures.slidersTexture;
        sdi.setSourceRect( 0.25,0, 0.75, 1 );
        sdi.a = scrollBarVisibility;
        if (sdi.a>1.0f) sdi.a = 1.0f;

        sdi.setTargetPos(8, spriteBatch->getTargetHeight()/2 );
        sdi.setScale( spriteBatch->getTargetHeight()*3/4, 32 );
        sdi.angle = 3.14159f/2.0f;
        spriteBatch->draw( &sdi );

        sdi.setTargetPos( spriteBatch->getTargetWidth()/2, spriteBatch->getTargetHeight() - 72 );
        sdi.setScale( spriteBatch->getTargetWidth()*3/4, 32 );
        sdi.angle  = 0.0f;
        spriteBatch->draw( &sdi );

            // Moving parts
        sdi.setSourceRect( 0,0, 0.25, 1 );
        sdi.setScale(30,30);

        float camx = spriteBatch->getTargetWidth()/2.0f - cameraPos[0];
        float camy = spriteBatch->getTargetHeight()/2.0f - cameraPos[1];
        float worldWidth = level->getWidth() * BLOCK_SIZE;
        float worldHeight = level->getHeight() * BLOCK_SIZE;

        float ftemp = (((worldHeight/2.0f-camy) / -worldHeight));
        if (ftemp<-0.5f) ftemp = -0.5f;
        if (ftemp>0.5f) ftemp = 0.5f;
        ftemp *= spriteBatch->getTargetHeight()*3/4;
        sdi.setTargetPos( 8, spriteBatch->getTargetHeight()/2 + ftemp );
        spriteBatch->draw( &sdi );


        ftemp = (((worldWidth/2.0f-camx) / -worldWidth));
        if (ftemp<-0.5f) ftemp = -0.5f;
        if (ftemp>0.5f) ftemp = 0.5f;
        ftemp *= spriteBatch->getTargetWidth()*3/4;
        sdi.setTargetPos( spriteBatch->getTargetWidth()/2 + ftemp, spriteBatch->getTargetHeight()-72 );
        spriteBatch->draw( &sdi );

    }


    if (level->isGameOver()) {

            // Write "GAME OVER"
        writeText( spriteBatch, "GAME",
                  spriteBatch->getTargetWidth()/2-70*4*FONT_X_INC_MUL/2+35*FONT_X_INC_MUL - spriteBatch->getTargetWidth()*finishedCounter,
                  spriteBatch->getTargetHeight()*0.35f-40, 70 );

        writeText( spriteBatch, "OVER",
                  spriteBatch->getTargetWidth()/2-70*4*FONT_X_INC_MUL/2+35*FONT_X_INC_MUL + spriteBatch->getTargetWidth()*finishedCounter,
                  spriteBatch->getTargetHeight()*0.35f+40, 70 );
    }

    if (level->isLevelCompleted()) {

            // Write "LEVEL CLEAR"
        writeText( spriteBatch, "LEVEL",
                  spriteBatch->getTargetWidth()/2-70*5*FONT_X_INC_MUL/2+35*FONT_X_INC_MUL - spriteBatch->getTargetWidth()*finishedCounter,
                  spriteBatch->getTargetHeight()*0.35f-40, 70 );
        writeText( spriteBatch, "CLEAR",
                  spriteBatch->getTargetWidth()/2-70*5*FONT_X_INC_MUL/2+35*FONT_X_INC_MUL  + spriteBatch->getTargetWidth()*finishedCounter,
                  spriteBatch->getTargetHeight()*0.35f+40, 70 );
    }



}


void TheGame::render() {

    spriteBatch->begin();

    if (!level) {
        // background.
    spriteBatch->draw( gameTextures.bgTexture,
                       spriteBatch->getTargetWidth()/2,spriteBatch->getTargetHeight()/2,
                       spriteBatch->getTargetWidth()*1.1f,spriteBatch->getTargetHeight()*1.1f );
    } else {

    }



    if (level) {
        level->render( spriteBatch, cameraPos[0],cameraPos[1] );
        renderHud();
    } else renderMainScreen();


    if (menu) menu->render();

    if (particles)
        particles->render( cameraPos[0],cameraPos[1], &starSpray );

    // close button
    SpriteDrawInfo sdi;
    sdi.textureHandle = gameTextures.iconTexture;
    if (!level) {
        // "X" button
        sdi.setSourceRect(0.75,0.0f, 0.125f, 0.25f );
    } else {
        // Arrowdown-button
        sdi.setSourceRect(0.75+0.125f,0.0f, 0.125f, 0.25f );
    }

    sdi.setTargetPos( spriteBatch->getTargetWidth() - 40, spriteBatch->getTargetHeight() - 40 );
    if (closeButtonActivated == false) {
        sdi.a = 0.75f;
        sdi.r = 0.5f;
        sdi.g = 0.5f;
        sdi.b = 0.5f;
    }
    sdi.setScale( 80,80 );
    spriteBatch->draw( &sdi );

    spriteBatch->end();
    spriteBatch->begin( SpriteBatch::eADDITIVE );


    if (particles)
        particles->render( cameraPos[0],cameraPos[1], &explosionSpray );

    if (particles)
        particles->render( cameraPos[0],cameraPos[1], &sparkleSpray, true );

    spriteBatch->end();

}


/**
 *
 * Render custom text with the font
 *
 */
void TheGame::writeText( SpriteBatch *batch, const char *text, float x, float y, float size, float *color ) {
    SpriteDrawInfo sdi;
    sdi.setScale(size);
    if (color) sdi.setColor(color);
    sdi.textureHandle = gameTextures.fontTexture;

    float xlen =  36.0f/1024.0f;
    float ylen =  58/256.0f;
    float sx,sy;
    int chpos, xpos,ypos;
    while (*text!=0) {
        if (*text!=' ') {
            chpos = *text - 32;
            ypos = (chpos>>4);
            xpos = chpos - (ypos<<4);
            sx = 35.0f/1024.0f + (986.0f-35.0f)/1024.0f*(float)xpos/15.0f - xlen/2.0f;
            //sy = (float)ypos/4.0f;
            sy = 31.0f/256.0f +  (218-31)/256.0f * (float)ypos/3.0f  - ylen/2.0f;
            sdi.setTargetPos(x,y);
            sdi.setSourceRect(sx,sy, xlen, ylen );
            batch->draw( &sdi );
        }

        x+=size*FONT_X_INC_MUL;
        text++;
    }
}
